﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Objects;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DevExpress.XtraReports.UI;
using RedRiver.Framework.XtraCommon.UserAuthentication;

namespace RedRiver.Framework.XtraCommon.Reports.Entities{
    partial class ReportEntities{

        public static ReportLayout GetReportLayout(string reportType,string reportName){
            return Instance.GetReportLayout(reportType, reportName, UserContext.GlobalConst.ApplicationName);
        }

        public ReportLayout GetReportLayout(string reportType,string reportName, string appDomain){
            int count = ReportLayout.Count(r => r.AppMomain == appDomain && r.ReportType == reportType && r.ReportName == reportName);
            if (count == 1){
                return ReportLayout.FirstOrDefault(r => r.AppMomain == appDomain && r.ReportType == reportType && r.ReportName == reportName);
            }
            if (count > 1){
                var selector = new ReportLayoutSelector(appDomain, reportName);
                if (selector.ShowDialog() == DialogResult.OK){
                    return selector.GetSelected();
                }
                return null;
            }
            var layout = new ReportLayout{
                                             ReportId = Guid.NewGuid(),
                                             AppMomain = appDomain,
                                             ReportType = reportType,
                                             ReportName = reportName,
                                             PaperKind = (int) PaperKind.Custom
                                         };
            ReportLayout.AddObject(layout);
            SaveChanges();
            return layout;
        }

        public override int SaveChanges(SaveOptions options) {
            IEnumerable<ReportLayout> list =
                ObjectStateManager.GetObjectStateEntries(EntityState.Deleted).Select(e => e.Entity).OfType
                    <ReportLayout>();
            foreach (ReportLayout item in list) {
                DeleteObject(item.LayoutContentReference.CreateSourceQuery().FirstOrDefault());
            }
            return base.SaveChanges(options);
        }
    }

    partial class ReportLayout{
        private XtraReport _report;

        /// <summary>
        /// 报表内容数据流
        /// </summary>
        public Stream Content{
            get{
                if (LayoutContent == null){
                    return null;
                }
                return new MemoryStream(LayoutContent.CompressionData).GetDecompressStream();
            }
            set{
                if (LayoutContent == null){
                    LayoutContent = new LayoutContent{Id = ReportId,CompressionData = new byte[0]};
                }
                LayoutContent.CompressionData = value.GetCompressStream().ToArray();
                LayoutContent.Length = LayoutContent.CompressionData.Length;
                LayoutContent.ContentType = "Repx";
            }
        }

        private void SetReportInfo(XtraReport report){
            report.Name = ReportName;
            report.DisplayName = DisplayName;
            report.PageHeight = PageHeight;
            report.PageWidth = PageWidth;
            report.PaperKind = (PaperKind) PaperKind;
        }

        /// <summary>
        /// 从 <see cref="Content"/> 获取 报表对象实例
        /// 如果 <see cref="Content"/> 不存在,新建一个报表对象
        /// </summary>
        /// <returns></returns>
        public XtraReport GetReport(){
            if (Content == null){
                _report = new XtraReport();
                SetReportInfo(_report);
                return _report;
            }
            if ((_report == null) || (_report.IsDisposed)){
                using (var stream = Content){
                    _report = XtraReport.FromStream(stream, true);
                }
                SetReportInfo(_report);
            }
            return _report;
        }

        /// <summary>
        /// 获取报表并加载数据源
        /// </summary>
        /// <param name="dataSource"></param>
        /// <returns></returns>
        public XtraReport GetReport(object dataSource){
            var report = GetReport();
            //绑定数据
            if ((report.DataSource != null) && (report.DataSource is BindingSource)) {
                ((BindingSource)report.DataSource).DataSource = dataSource;
            } else {
                report.DataSource = new BindingSource(dataSource, string.Empty);
            }
            return report;
        }

        /// <summary>
        /// 序列化 报表,<see cref="XtraReport.SaveLayout(Stream)">保存报表布局</see> 
        /// 到 <see cref="Content">Body 属性</see>
        /// 包括 <see cref="PaperKind"/>,<see cref="PaperName"/>,<see cref="PageHeight"/>
        /// <see cref="PageWidth"/>,<see cref="DisplayName"/>
        /// 不包括<see cref="ReportName"/>属性
        /// </summary>
        /// <param name="report"></param>
        public void SerializaReport(XtraReport report){
            using (var stream = new MemoryStream()){
                PaperKind = (int) report.PaperKind;
                PaperName = report.PaperName;
                PageHeight = report.PageHeight;
                PageWidth = report.PageWidth;
                DisplayName = report.DisplayName;
                report.SaveLayout(stream);
                Content = stream;
            }
            _report = report;
        }

        /// <summary>
        /// 加载报表实例
        /// </summary>
        /// <param name="report"></param>
        /// <returns></returns>
        public XtraReport GetReport(XtraReport report){
            if (Content == null){
                return report;
            }
            if ((_report == null) || (_report.IsDisposed)){
                using (var stream = Content){
                    report.LoadLayout(stream);
                    _report = report;
                    SetReportInfo(_report);
                }
            }
            return _report;
        }
    }
}